Skip to content

Conversation

@dicej
Copy link
Contributor

@dicej dicej commented Jan 14, 2026

This commit makes a few changes related to recursive reentrance checks, instance poisoning, etc.:

  • Implements the more restrictive lift/lower rules described in Refine recursion check to handle child import/export forwarding WebAssembly/component-model#589 such that a component instance may not lower a function lifted by one of its ancestors, nor vice-versa. Any such lower will result in a fused adapter which traps unconditionally, preventing guest-to-guest recursive reentrance without requiring data flow analysis.
    • Note that this required updating several WAST tests which were violating the new rule, including some in the tests/component-model Git submodule, which I've updated.
    • This is handled entirely in the fact module now; I've removed the AlwaysTrap case previously handled by wasmtime-cranelift.
  • Removes FLAG_MAY_ENTER from InstanceFlags. It is no longer needed for guest-to-guest calls due to the above, and for guest-to-host-to-guest calls we can rely on either FLAG_NEEDS_POST_RETURN for sync-lifted functions or the GuestTask call stack for async-lifted functions.
  • Adds a StoreOpaque::trapped field which is set when any instance belonging to that store traps, at which point the entire store is considered poisoned, meaning no instance belonging to it may be entered. This prevents indeterminant concurrent task state left over from the trapping instance from leaking into other instances.

Note that this does not include code to push and pop GuestTask instances for guest-to-guest sync-to-sync calls, nor for host-to-guest calls using e.g. the synchronous Func::call API, so certain intrinsics which expect a GuestTask to be present such as backpressure.inc will still fail in such cases. I'll address that in a later PR.

Also note that I made a small change to wasmtime-wit-bindgen, adding a Send bound on the T type parameter for store | async functions. This allowed me to recursively call {Typed}Func::call_concurrent from inside a host function, and it doesn't have any downsides AFAICT.

Fixes #12128

This commit makes a few changes related to recursive reentrance checks, instance
poisoning, etc.:

- Implements the more restrictive lift/lower rules described in WebAssembly/component-model#589 such that a component instance may not lower a function lifted by one of its ancestors, nor vice-versa.  Any such lower will result in a fused adapter which traps unconditionally, preventing guest-to-guest recursive reentrance without requiring data flow analysis.
    - Note that this required updating several WAST tests which were violating the new rule, including some in the `tests/component-model` Git submodule, which I've updated.
    - This is handled entirely in the `fact` module now; I've removed the `AlwaysTrap` case previously handled by `wasmtime-cranelift`.
- Removes `FLAG_MAY_ENTER` from `InstanceFlags`.  It is no longer needed for guest-to-guest calls due to the above, and for guest-to-host-to-guest calls we can rely on either `FLAG_NEEDS_POST_RETURN` for sync-lifted functions or the `GuestTask` call stack for async-lifted functions.
- Adds a `StoreOpaque::trapped` field which is set when _any_ instance belonging to that store traps, at which point the entire store is considered poisoned, meaning no instance belonging to it may be entered.  This prevents indeterminant concurrent task state left over from the trapping instance from leaking into other instances.

Note that this does _not_ include code to push and pop `GuestTask` instances for
guest-to-guest sync-to-sync calls, nor for host-to-guest calls using e.g. the
synchronous `Func::call` API, so certain intrinsics which expect a `GuestTask`
to be present such as `backpressure.inc` will still fail in such cases.  I'll
address that in a later PR.

Also note that I made a small change to `wasmtime-wit-bindgen`, adding a `Send`
bound on the `T` type parameter for `store | async` functions.  This allowed me
to recursively call `{Typed}Func::call_concurrent` from inside a host function,
and it doesn't have any downsides AFAICT.

Fixes bytecodealliance#12128
@dicej dicej requested a review from alexcrichton January 14, 2026 17:39
@dicej dicej requested review from a team as code owners January 14, 2026 17:39
Copy link
Member

@alexcrichton alexcrichton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor comments here and there, but overall looks great, thanks!

@dicej dicej enabled auto-merge January 14, 2026 20:27
@dicej dicej force-pushed the reentrance-refactor-part1 branch from deb61e1 to a60e7f7 Compare January 14, 2026 20:28
@dicej dicej added this pull request to the merge queue Jan 14, 2026
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 14, 2026
@dicej dicej enabled auto-merge January 14, 2026 21:59
...and add const assertions to `trap.rs` to help avoid future divergence.
@dicej dicej force-pushed the reentrance-refactor-part1 branch from c0024b8 to 1ffadaa Compare January 14, 2026 22:12
@dicej dicej added this pull request to the merge queue Jan 14, 2026
Merged via the queue into bytecodealliance:main with commit b856261 Jan 14, 2026
49 checks passed
@dicej dicej deleted the reentrance-refactor-part1 branch January 14, 2026 22:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

component-model-async: Cannot reenter component during a task's yield?

2 participants